import numpy as np
import matplotlib.pyplot as plt
# y = wx + b
def compute_error_for_line_given_points(b, w, points):
    totalError = 0
    for i in range(0 , len(points)):
        x = points[i, 0]
        y = points[i, 1]
        #计算均方误差
        totalError += (y - (w * x + b) ) ** 2
    return totalError / float(len(points))

#使用梯度下降法跟新系数和误差
def step_gradient(b_current, w_current, points, learningRate):
    b_gradient = 0
    w_gradient = 0
    N = float(len(points))
    for i in range(0, len(points)):
        x = points[i, 0]
        y = points[i, 1]
        #计算偏导梯度
        b_gradient += (2/N) * ((w_current * x + b_current) - y)
        w_gradient += (2/N) * x * ((w_current * x + b_current) - y)

    #根据学习率跟新w系数和b误差
    new_b = b_current - (learningRate * b_gradient)
    new_w = w_current - (learningRate * w_gradient)

    return [new_b, new_w]


def gradient_descent_runner(points, starting_b, starting_w, learning_rate, num_iterations):
    b = starting_b
    w = starting_w
    for i in range(num_iterations):
        b, w = step_gradient(b, w, np.array(points), learning_rate)
    return [b, w]

def drawpic(points, b , w):
    x = points[:, 0]
    y = points[:, 1]
    x1= np.linspace(20, 80, 2)
    y1 = w * x1 + b
    labely = 'y = {0}* x + {1}'.format(w, b)
    # 2.创建画布
    plt.figure(figsize=(15, 8), dpi=80)
    plt.title('线性回归实现')
    # 3.绘制图像
    plt.scatter(x, y)
    plt.plot(x1,y1,'-r',label=labely)
    plt.legend()
    plt.grid()
    # 4.显示图像
    plt.show()

def run():

    points = np.genfromtxt('data.csv', delimiter=',')
    learning_rate = 0.0001
    init_b = 0
    init_w = 0
    num_iterations = 10000
    print('Starting gradient descent at b = {0}, w = {1}, error = {2}'.
          format(init_b, init_w,compute_error_for_line_given_points(init_b, init_w, points ) ))
    print('运行中。。。。。')
    [b, w] = gradient_descent_runner(points, init_b, init_w, learning_rate, num_iterations)
    print("After {0} iterations b = {1}, w = {2}, error = {3}".
          format(num_iterations, b, w, compute_error_for_line_given_points(b, w, points)) )
    drawpic(points, b , w)

if __name__ == '__main__':
    run()